import random

from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django_redis import get_redis_connection

from app01 import models
from app01.modelforms.bootstrap import BootstrapForm
from utils.encrypt import md5
from utils.tencent.sms import send_sms_single


# 生成表单&校验字段
class RegisterModelform(BootstrapForm, forms.ModelForm):
    # 生成表单
    password = forms.CharField(
        label="密 码",
        widget=forms.PasswordInput(),  # 把密码控件改成密文
        min_length=8,
        max_length=64,
        error_messages={
            'min_length': '长度不能小于8位',
            'max_length': '长度不能大于64位'
        }
    )
    confirm_password = forms.CharField(
        label="重复密码",
        widget=forms.PasswordInput(),  # 把密码控件改成密文
        min_length=8,
        max_length=64,
        error_messages={
            'min_length': '长度不能小于8位',
            'max_length': '长度不能大于64位'
        }
    )
    mobile_phone = forms.CharField(label='手机号',
                                   validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', "手机号格式错误！！！"), ])
    code = forms.CharField(label="验证码", widget=forms.TextInput())

    class Meta:
        model = models.UserInfo
        fields = ['name', 'password', 'confirm_password', 'email', 'mobile_phone', 'code']

    # 用户名
    def clean_name(self):
        name = self.cleaned_data.get('name')
        existis = models.UserInfo.objects.filter(name=name).exists()
        if existis:
            self.add_error('name', "用户名已存在！")
        return name

    # 邮箱
    def clean_email(self):
        email = self.cleaned_data.get('email')
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            # raise ValidationError('该邮箱已绑定！')
            self.add_error('email', '该邮箱已绑定！')
        return email

    # 密码加密处理
    def clean_password(self):
        pwd = self.cleaned_data.get('password')
        # 加密 & 返回
        return md5(pwd)

    # 确认密码
    def clean_confirm_password(self):
        pwd = self.cleaned_data.get('password')
        confirm_password = md5(self.cleaned_data.get('confirm_password'))
        if confirm_password != pwd:
            self.add_error('confirm_password', '两次密码输入不一致')
        return confirm_password

    # 手机号
    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data.get('mobile_phone')
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            self.add_error('mobile_phone', '手机号已注册！')
        return mobile_phone

    # 验证码
    def clean_code(self):
        code = self.cleaned_data.get('code')
        mobile_phone = self.cleaned_data.get('mobile_phone')
        print(code, mobile_phone)
        if not mobile_phone:
            raise ValidationError('未输入手机号！')
        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError('验证码失效或未发送，请重新发送')
        str_code = redis_code.decode('utf-8')
        if str(code).strip() != str_code:
            raise ValidationError('验证码输入错误，请重新输入')
        return code


# 验证码发送校验
class SendSmsForm(forms.Form):
    # 检验手机格式
    mobile_phone = forms.CharField(label='手机号',
                                   validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', "手机号格式错误！！！"), ])

    # 重写__init__函数，传入request
    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_phone(self):
        """号码校验的钩子"""
        mobile_phone = self.cleaned_data['mobile_phone']  # 手机号
        tpl = self.request.GET.get('tpl')
        template_id = settings.TENCENT_SMS_APP_TPL[tpl]  # 短信模板ID

        # 判断短信模板参数
        if not template_id:
            raise ValidationError("模板报错")

        # 判断手机号是否存在
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if tpl == 'sign':
            if not exists:
                raise ValidationError("手机号未注册！")
        elif exists:
            raise ValidationError("手机号已注册！")

        # 发送短信 & redis
        code = random.randrange(1000, 9999)
        if tpl == 'sign':
            sms = send_sms_single(mobile_phone, template_id, [code, ])
        else:
            sms = send_sms_single(mobile_phone, template_id, [code, 60])
        if sms['result'] != 0:
            raise ValidationError('短信发送失败', sms)

        # code 写入redis
        conn = get_redis_connection()
        conn.set(mobile_phone, code, ex=60)
        return mobile_phone


# 短信登录
class LoginSMSForm(BootstrapForm, forms.Form):
    mobile_phone = forms.CharField(label='手机号',
                                   validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', "手机号格式错误！！！"), ])
    code = forms.CharField(label="验证码", widget=forms.TextInput())

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data.get('mobile_phone')
        user_object = models.UserInfo.objects.filter(mobile_phone=mobile_phone).first()
        if not user_object:
            raise ValidationError('手机号未注册！')
        return user_object

    def clean_code(self):
        code = self.cleaned_data.get('code')
        user_object = self.cleaned_data.get('mobile_phone')
        if not user_object:
            raise ValidationError('未输入手机号！')
        conn = get_redis_connection()
        redis_code = conn.get(user_object.mobile_phone)
        if not redis_code:
            raise ValidationError('验证码失效或未发送，请重新发送！')
        str_code = redis_code.decode('utf-8')
        if str(code).strip() != str_code:
            raise ValidationError('验证码输入错误，请重新输入')
        return code


# 账号密码 图片验证码登录
class LoginPasswordForm(BootstrapForm, forms.Form):
    username = forms.CharField(label='手机号或邮箱')
    mobile_password = forms.CharField(label="密码", widget=forms.PasswordInput(render_value=True))  # render_value=True
    code = forms.CharField(label="图片验证码", widget=forms.TextInput())

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_password(self):
        pwd = self.cleaned_data.get('mobile_password')
        # 加密 & 返回
        mobile_password = md5(pwd)
        return mobile_password

    def clean_code(self):
        code = self.cleaned_data.get('code')  # 获取用户输入的验证码

        session_code = self.request.session.get('image_code')  # 获取session里的验证码
        if not session_code:
            raise ValidationError("验证码已过期,请重新获取！")
        if str(code).upper().strip().replace(' ', '') != str(session_code).upper():
            raise ValidationError("验证码输入错误,请重新输入！")
        return code
